//
// Created by shaowenhan on 2020/3/7.
//

#include "ReadParameters.h"

void ReadParameters::exitIfValueNotInRange(const double &minimal, const double &maximal, const double &value,
                                           const string &parName) {
    if(isFirstGreaterThanSecond(minimal, value) or isFirstLessThanSecond(maximal, value))
    {
        DLOG(ERROR)<<"parameter "<<parName<<" should be in ["<<minimal<<", "<<maximal<<"]";
        exit(EXIT_FAILURE);
    }
}

int ReadParameters::doubleParMultiFactor(const Json::Value &value, const string &key, int factor) {
    return static_cast<int>(value[key].asDouble() * factor);
}

int ReadParameters::ceilDoubleParMultiFactor(const Json::Value &value, const string &key, int factor) {
    return static_cast<int>(ceil(value[key].asDouble() * factor));
}

double ReadParameters::changeFactor(double maxVal, double minVal, int steps) {
    return exp(log(maxVal/minVal)/steps);
}

void
ReadParameters::obtainParametersForGTSControl(const Json::Value &value, ParameterForGTSControl &parameterForGTSControl,
                                              int cusNum) {
    parameterForGTSControl.minCusNum = value["minCusNum"].asInt();
    parameterForGTSControl.maxCusNum = value["maxCusNum"].asInt();
    parameterForGTSControl.changeFactorForCus = changeFactor(parameterForGTSControl.maxCusNum, parameterForGTSControl.minCusNum, value["stepsFromMinToMaxForCus"].asInt());

    parameterForGTSControl.minDepotNum = value["minDepotNum"].asInt();
    parameterForGTSControl.maxDepotNum = value["maxDepotNum"].asInt();
    parameterForGTSControl.changeFactorForDepot = changeFactor(parameterForGTSControl.maxDepotNum, parameterForGTSControl.minDepotNum, value["stepsFromMinToMaxForDepot"].asInt());
    auto updatingGranularThresFactor = value["updatingGranularThresFactor"].asInt();
    if(updatingGranularThresFactor == 0)
        updatingGranularThresFactor = cusNum;
    parameterForGTSControl.iteForUpdatingGranularThres = ceilDoubleParMultiFactor(value,
                                                                                  "iteForUpdatingGranularThresRatio",
                                                                                  updatingGranularThresFactor);
    parameterForGTSControl.isAllDepotsUsedForAllMoveTypes = value["isAllDepotsUsedForAllMoveTypes"].asBool();
}

void ReadParameters::obtainParametersForAttTabu(const Json::Value &value, ParameterForAttTabu &parameterForAttTabu,
                                                int cusNum) {
    auto tabuFactor = value["tabuFactor"].asInt();
    if(tabuFactor == 0)
        tabuFactor = cusNum;
    parameterForAttTabu.minimalTabuTenure = ceilDoubleParMultiFactor(value, "ratioOfCusToMinimumTabuTenure", tabuFactor);
    parameterForAttTabu.maximalTabuTenure = parameterForAttTabu.minimalTabuTenure +
            doubleParMultiFactor(value, "lengthRatio", tabuFactor);
    parameterForAttTabu.setTabuCriterion(value["attTabuCriterion"].asString());
}

void ReadParameters::obtainParametersForSolTabu(const Json::Value &value, ParameterForSolTabu &parameterForSolTabu) {
    parameterForSolTabu.hashTableNum = value["hashTableNum"].asInt();
    parameterForSolTabu.maxVisitTime = value["maxVisitTime"].asInt();
}

void ReadParameters::obtainParametersForPenaltyFactor(const Json::Value &value,
                                                      ParameterForPenaltyFactor &parameterForPenaltyFactor)
{
    parameterForPenaltyFactor.initialPenaltyFac.resize(Constraint::num);
    parameterForPenaltyFactor.minimalPenaltyFac.resize(Constraint::num);
    parameterForPenaltyFactor.maximalPenaltyFac.resize(Constraint::num);

    parameterForPenaltyFactor.initialPenaltyFac[Constraint::vehicleCap] = value["initialVehicleCapPenaltyFac"].asDouble();
    parameterForPenaltyFactor.minimalPenaltyFac[Constraint::vehicleCap] = value["minimalVehicleCapPenaltyFac"].asDouble();
    parameterForPenaltyFactor.maximalPenaltyFac[Constraint::vehicleCap] = value["maximalVehicleCapPenaltyFac"].asDouble();
#if defined(MDVRP)
    parameterForPenaltyFactor.initialPenaltyFac[Constraint::duration] = value["initialRouteTimePenaltyFac"].asDouble();
    parameterForPenaltyFactor.minimalPenaltyFac[Constraint::duration] = value["minimalRouteTimePenaltyFac"].asDouble();
    parameterForPenaltyFactor.maximalPenaltyFac[Constraint::duration] = value["maximalRouteTimePenaltyFac"].asDouble();
#elif defined(LRP)
    parameterForPenaltyFactor.initialPenaltyFac[Constraint::depotCap] = value["initialDepotCapPenaltyFac"].asDouble();
    parameterForPenaltyFactor.minimalPenaltyFac[Constraint::depotCap] = value["minimalDepotCapPenaltyFac"].asDouble();
    parameterForPenaltyFactor.maximalPenaltyFac[Constraint::depotCap] = value["maximalDepotCapPenaltyFac"].asDouble();
#endif
    parameterForPenaltyFactor.changeFactor = value["changeFactor"].asDouble();
}

void ReadParameters::obtainParametersForGTSTermination(const Json::Value &value,
                                                       ParameterForGTSTermination &parameterForGTSTermination,
                                                       int cusNum, const string &suffix) {
    parameterForGTSTermination.setGTSTerminationCriterion(value["terminateCriterion"+suffix].asString());
    parameterForGTSTermination.maxTabuSearchRunningTime = value["maxTabuSearchRunningTime"+suffix].asInt();
    parameterForGTSTermination.maximalRunningSteps = static_cast<int>(value["maximalRunningStepsRatio"+suffix].asDouble()*cusNum);
    auto maximalUnImprovementStepsRatio = value["maximalUnImprovementStepsRatio"+suffix].asDouble();
    if(maximalUnImprovementStepsRatio >= 0)
        parameterForGTSTermination.maximalUnImprovementSteps = static_cast<int>(maximalUnImprovementStepsRatio*cusNum);
    else
        parameterForGTSTermination.maximalUnImprovementSteps = static_cast<int>(maximalUnImprovementStepsRatio*-1);
}

void
ReadParameters::obtainParametersForRoutesPool(const Json::Value &value,
                                              ParameterForRoutesPoolControl &parameterForRoutesPool,
                                              int cusNum)
{
    parameterForRoutesPool.setRoutesPoolUpdateMethod(value["RoutesPoolUpdateMethod"].asString());
    parameterForRoutesPool.maxRoutesPoolSize = value["maxRoutesPoolSize"].asInt();
    obtainParametersForGTSTermination(value, parameterForRoutesPool.parameterForGtsTerminationForInitialRoutesPool, cusNum, "ForIniRoutesPool");
    obtainParametersForGTSTermination(value, parameterForRoutesPool.parameterForGtsTerminationForImprovement, cusNum, "ForImproveSolOfModel");
    parameterForRoutesPool.routesPoolSize = min(parameterForRoutesPool.maxRoutesPoolSize, value["routesPoolSizeRatio"].asInt()*cusNum);
    parameterForRoutesPool.maxRunTimeForInitialRoutesPool = value["maxRunTimeRatioForInitialRoutesPool"].asDouble()*cusNum;
    parameterForRoutesPool.maximalModelRunningTime = static_cast<int>(cusNum*value["maximalModelRunningTimeRatio"].asDouble());
}

void
ReadParameters::obtainParametersForDiversity(const Json::Value &value, ParameterForDiversity &parameterForDiversity,
                                             int cusNum)
{
    parameterForDiversity.diversificationIntensity = value["diversificationIntensity"].asDouble();
    parameterForDiversity.deteriorationDegree = value["deteriorationDegree"].asDouble();
    auto unImprovementStepsForConsiderPerturbationRatio = value["unImprovementStepsForConsiderPerturbationRatio"].asDouble();
    if(unImprovementStepsForConsiderPerturbationRatio >= 0)
        parameterForDiversity.unImprovementStepsForConsiderPerturbation = static_cast<int>(cusNum * unImprovementStepsForConsiderPerturbationRatio);
    else
        parameterForDiversity.unImprovementStepsForConsiderPerturbation = static_cast<int>(-1*unImprovementStepsForConsiderPerturbationRatio);
    auto perturbationStepsRatio = value["perturbationStepsRatio"].asDouble();
    if(perturbationStepsRatio >= 0)
        parameterForDiversity.perturbationSteps = static_cast<int>(cusNum*perturbationStepsRatio);
    else
        parameterForDiversity.perturbationSteps = static_cast<int>(-1*perturbationStepsRatio);
    parameterForDiversity.umImprovementStepsBackToHistoricalSol = doubleParMultiFactor(value,"umImprovementStepsBackToHistoricalSolRatio",cusNum);
    parameterForDiversity.unImprovementStepsToReverseRoutes = value["unImprovementStepsToReverseRoutes"].asInt();
    const auto &moveTypesUsedInPerturbation = value["moveTypesUsedInPerturbation"];
    parameterForDiversity.moveTypesUsedInPerturbation.clear();
    for(const auto& moveType: moveTypesUsedInPerturbation)
        parameterForDiversity.moveTypesUsedInPerturbation.emplace_back(MoveTypeAuxFunc::moveTypeStrToMoveType(moveType.asString()));
    parameterForDiversity.deteriorationDegreeBackToHisSol = value["deteriorationDegreeBackToHisSol"].asDouble();
    parameterForDiversity.deteriorationDeltaBackToHisSol = value["deteriorationDeltaBackToHisSol"].asDouble();
}

void
ReadParameters::obtainParametersForPopulation(const Json::Value &value, ParameterForPopulation &parameterForPopulation,
                                              int cusNum) {
    auto &parForIniSolConstruct = parameterForPopulation.parForInitialSolConstruct;

    obtainParametersForGTSTermination(value, parForIniSolConstruct.parForGTSTerminateWhenObtainFeasibleSol, cusNum, "ForFeasibleSols");
    obtainParametersForDisBetSol(value, "ForPop", parForIniSolConstruct.parForDisBetSol);

    auto &parForTwoIndividuals = parameterForPopulation.parameterForTwoIndividuals;
    parForTwoIndividuals.cycle = value["cycleOfGeneration"].asInt();
    parForTwoIndividuals.maximalReinitializationCountWhenSolSimilar = value["maxInitialCountWhenSolSimilar"].asInt();
    parForTwoIndividuals.solSimilarityDis = static_cast<int>(cusNum * value["solSimilarityDisRatio"].asDouble());
    parForTwoIndividuals.isQualityConsideredToUpdateParent = value["isQualityConsideredToUpdateParent"].asBool();

    auto &parForLargePop = parameterForPopulation.parameterForLargePop;
    parForLargePop.populationSize = value["populationSize"].asInt();
    parForLargePop.setUpdatePopCriterion(value["updatePopCriterion"].asString());
    parForLargePop.surviveSolNum = max(static_cast<int>(ceil(value["ratioOfSurviveSolNumToPopSize"].asDouble() * parForLargePop.populationSize)), 1);
    parForLargePop.isCusAssignedToDepotInLastGeneration = value["isCusAssignedToDepotInLastGeneration"].asBool();
    parForLargePop.unImprovedStepsToEnergizePop = value["unImprovedStepsToEnergizePop"].asInt();
    parForLargePop.isWholePopEvolvedTogether = value["isWholePopEvolvedTogether"].asBool();
    obtainParametersForFitness(value, parForLargePop.parameterForFitness, cusNum);

    auto solNumRatioOfDifDiversity = value["solNumRatioOfDifDiversity"];
#if defined(TwoIndividuals)
    int popSize = 2;
#elif defined(LargePopulation)
    int popSize = parForLargePop.populationSize;
#endif
    for(auto & i : solNumRatioOfDifDiversity)
        parForIniSolConstruct.solNumOfDifDiversity.emplace_back(static_cast<int>(ceil(popSize * i.asDouble())));
    auto sum = std::accumulate(parForIniSolConstruct.solNumOfDifDiversity.begin(), parForIniSolConstruct.solNumOfDifDiversity.end(), 0);
    auto delta = sum-popSize;
    if(delta > 0){
        for(int i = 1; delta ; ){
            if(parForIniSolConstruct.solNumOfDifDiversity[i]){
                parForIniSolConstruct.solNumOfDifDiversity[i]--;
                delta--;
            }
            i = (i+1)%static_cast<int>(parForIniSolConstruct.solNumOfDifDiversity.size());
            if(i == 0)
                i++;
        }
        while(parForIniSolConstruct.solNumOfDifDiversity.back() == 0)
            parForIniSolConstruct.solNumOfDifDiversity.pop_back();
    }
    else if(delta < 0)
        parForIniSolConstruct.solNumOfDifDiversity.back() -= delta;
}

void ReadParameters::obtainParametersForFitness(const Json::Value &value, ParameterForFitness &parameterForFitness,
                                                int cusNum) {
    parameterForFitness.setDiversityCriterion(value["diversityCriterion"].asString());
    parameterForFitness.fitnessFactor = value["ratioOfCusCountToDis"].asDouble() * cusNum;
}

void ReadParameters::obtainParametersForPathRelinking(const Json::Value &value,
                                                      ParameterForPathRelinking &parameterForPathRelinking)
{
    parameterForPathRelinking.terminationDistanceFactor = value["terminationDisFac"].asDouble();
    parameterForPathRelinking.putIntoPathSetShortestDisFac = value["putIntoPathSetShortestDisFac"].asDouble();
    parameterForPathRelinking.solNumInEachStep = value["solNumInEachStep"].asInt();
    obtainParametersForDisBetSol(value, "ForPR", parameterForPathRelinking.parameterForDisBetSol);
}

void ReadParameters::obtainParametersForSolveStrategy(const Json::Value &value,
                                                      ParameterForSolveStrategy &parameterForSolveStrategy)
{
    parameterForSolveStrategy.setSolveStrategy(value["SolveStrategy"].asString());
    parameterForSolveStrategy.runNum = value["RunNum"].asInt();
    for(const auto& seed: value["randomSeed"])
        parameterForSolveStrategy.inputRandomSeed.emplace_back(seed.asInt());
    while(parameterForSolveStrategy.inputRandomSeed.size() < parameterForSolveStrategy.runNum)
        parameterForSolveStrategy.inputRandomSeed.emplace_back(-1);
    random_device randomDevice;
    for(auto seed: parameterForSolveStrategy.inputRandomSeed){
        if(seed == -1)
            parameterForSolveStrategy.realRandomSeed.emplace_back(randomDevice());
        else
            parameterForSolveStrategy.realRandomSeed.emplace_back(seed);
    }
}

void ReadParameters::obtainParametersForMoveTypesInDifLevelOrGroup(const Json::Value &value,
                                                                   vector<vector<MoveType>> &moveTypesInDifLevelOrGroup,
                                                                   const string &suffix) {
    const auto &moveTypesInDifLevelOrGroupArray = value["moveTypesIn"+suffix];
    for(const auto& moveTypes: moveTypesInDifLevelOrGroupArray){
        vector<MoveType> tmp;
        for(const auto& moveType: moveTypes)
            tmp.emplace_back(MoveTypeAuxFunc::moveTypeStrToMoveType(moveType.asString()));
        moveTypesInDifLevelOrGroup.emplace_back(std::move(tmp));
    }
}

void ReadParameters::obtainParametersForChooseMoveTypes(const Json::Value &value,
                                                        ParameterForChooseMoveTypes &parameterForChooseMoveTypes,
                                                        int cusNum) {
    parameterForChooseMoveTypes.setChooseMoveStrategy(value["chooseMoveStrategy"].asString());
    obtainParametersForAdaptiveMoveTypeChoose(value, parameterForChooseMoveTypes.parameterForAdaptiveMoveTypeChoose);
    obtainParametersForVNS(value, parameterForChooseMoveTypes.parameterForVNS, cusNum);
    obtainParametersForAdaptiveVNS(value, parameterForChooseMoveTypes.parameterForAdaptiveVNS, cusNum);
}

void ReadParameters::obtainParametersForAdaptiveMoveTypeChoose(const Json::Value &value,
                                                               ParameterForAdaptiveMoveTypeChoose &parameterForAdaptiveMoveTypeChoose) {
    parameterForAdaptiveMoveTypeChoose.minimalWeight = value["MinimalWeight"].asDouble();
    parameterForAdaptiveMoveTypeChoose.maximalWeight = value["MaximalWeight"].asDouble();
    parameterForAdaptiveMoveTypeChoose.discountFactor = value["DiscountFactor"].asDouble();
    parameterForAdaptiveMoveTypeChoose.penaltyFactorWhenFeasibleMoveNotExist = value["penaltyFactorWhenFeasibleMoveNotExist"].asDouble();
    parameterForAdaptiveMoveTypeChoose.initialPenalty = value["initialPenalty"].asDouble();
    parameterForAdaptiveMoveTypeChoose.ratioOfInitialWeightToMaxWeight = value["ratioOfInitialWeightToMaxWeight"].asDouble();
    parameterForAdaptiveMoveTypeChoose.speed = value["Speed"].asDouble();
    exitIfValueNotInRange(0, 1, parameterForAdaptiveMoveTypeChoose.discountFactor, "DiscountFactor");
    exitIfValueNotInRange(0, 1, parameterForAdaptiveMoveTypeChoose.speed, "Speed");
    parameterForAdaptiveMoveTypeChoose.isPresetWeightsUsed = value["isPresetWeightsUsed"].asBool();
    auto arrayValue = value["ratioOfPresetWeightsToMaxWeight"];
    for(const auto & weight : arrayValue)
        parameterForAdaptiveMoveTypeChoose.presetWeights.emplace_back(weight.asDouble()*parameterForAdaptiveMoveTypeChoose.maximalWeight);
    obtainParametersForMoveTypesInDifLevelOrGroup(value, parameterForAdaptiveMoveTypeChoose.moveTypesOfDifGroup, "DifGroup");
    parameterForAdaptiveMoveTypeChoose.isWeightClearedAfterResetSol = value["isWeightClearedAfterResetSol"].asBool();
}

void
ReadParameters::obtainParametersForVNSBasic(const Json::Value &value, ParameterForVNS &parameterForVNS, int cusNum,
                                            const string &suffix) {
    auto cycleFactor = value["cycleFactorFor"+suffix].asInt();
    if(cycleFactor == 0)
        cycleFactor = cusNum;
    auto cycleArrayValue = value["cycleRatioFor"+suffix];
    for(const auto & cycle: cycleArrayValue)
        parameterForVNS.cycle.emplace_back(static_cast<int>(ceil(cycle.asDouble()*cycleFactor)));
    parameterForVNS.isBackToFirstLevelAfterTraversingAllLevels = value["isBackToFirstLevelAfterTraversingAllLevelsFor"+suffix].asBool();
}

void ReadParameters::obtainParametersForVNS(const Json::Value &value, ParameterForVNS &parameterForVNS, int cusNum) {
    obtainParametersForVNSBasic(value, parameterForVNS, cusNum, "VNS");
    obtainParametersForMoveTypesInDifLevelOrGroup(value, parameterForVNS.moveTypesInDifLevelOrGroup, "DifLevelForVNS");
}

void
ReadParameters::obtainParametersForAdaptiveVNS(const Json::Value &value, ParameterForAdaptiveVNS &parForAdaptiveVNS,
                                               int cusNum) {
    const auto &moveTypeToLevelPossibility = value["moveTypeToLevelPossibility"];
    const auto & moveTypesArray = moveTypeToLevelPossibility["moveTypes"];
    const auto& levelArray = moveTypeToLevelPossibility["level"];
    const auto& possibilityArray = moveTypeToLevelPossibility["possibility"];

    for(int i = 0; i < moveTypesArray.size(); i++){
        vector<pair<int, double>> levelAndPossibility(levelArray[i].size());
        for(int j = 0; j < levelArray[i].size(); j++){
            levelAndPossibility[j] = make_pair(levelArray[i][j].asInt(), possibilityArray[i][j].asDouble());
        }
        parForAdaptiveVNS.moveTypeToLevelPossibility[MoveTypeAuxFunc::moveTypeStrToMoveType(moveTypesArray[i].asString())] = move(levelAndPossibility);
    }
    obtainParametersForVNSBasic(value, parForAdaptiveVNS, cusNum, "AdaptiveVNS");
    obtainParametersForMoveTypesInDifLevelOrGroup(value, parForAdaptiveVNS.moveTypesInDifLevelOrGroup, "DifLevelForAdaptiveVNS");
}

void ReadParameters::obtainParametersForGPX(const Json::Value &value, ParameterForGPX &parameterForGPX, int depotNum) {
    parameterForGPX.setPartitionGranularity(value["partitionGranularity"].asString());
    parameterForGPX.setAssignRestCusCriterion(value["AssignRestCusCriterion"].asString());
    parameterForGPX.possibilityOfAssignRestCusToFirstSol = value["possibilityOfAssignRestCusToFirstSol"].asDouble();

    auto &parForRoute = parameterForGPX.parameterForGpxWhenRouteIsGranularity;
    parForRoute.ratioOfCrossoverRoutesToAllRoutes = value["ratioOfCrossoverRoutesToAllRoutes"].asDouble();
    parForRoute.setRetainRouteCriterion(value["retainRouteCriterion"].asString());
    parForRoute.ratioOfRouteFromFirstSolToOneFromSecondSol = value["ratioOfRouteFromFirstSolToOneFromSecondSol"].asInt();

    auto &parForDepot = parameterForGPX.parameterForGpxWhenDepotIsGranularity;
    auto depotFromParentsWhenDepotCountIsOdd = value["depotFromParentsWhenDepotCountIsOdd"].asString();
    if(depotNum%2 == 0 or depotFromParentsWhenDepotCountIsOdd == "remainOneUnInherited")
        parForDepot.depotFromFirstSol = parForDepot.depotFromSecondSol = depotNum/2;
    else if(depotFromParentsWhenDepotCountIsOdd == "firstSolOneMore"){
        parForDepot.depotFromSecondSol = depotNum/2;
        parForDepot.depotFromFirstSol = parForDepot.depotFromSecondSol+1;
    }
    else if(depotFromParentsWhenDepotCountIsOdd == "secondSolOneMore"){
        parForDepot.depotFromFirstSol = depotNum/2;
        parForDepot.depotFromSecondSol = parForDepot.depotFromFirstSol+1;
    }
    parForDepot.setPartitionDepotCriterion(value["partitionDepotCriterion"].asString());
    parForDepot.setRetainDepotCriterion(value["RetainDepotCriterion"].asString());
}

void
ReadParameters::obtainParametersForDisBetSol(const Json::Value &value, const string &suffix,
                                             ParameterForDisBetSol &parForDisBetSol) {
    parForDisBetSol.weightOfCusByDifDepot = value["weightOfCusByDifDepot"+suffix].asDouble();
}

void
ReadParameters::obtainParametersForHybridAlg(const Json::Value &value, ParameterForHybridAlg &parForHybridAlg,
                                             int cusNum, int depotNum) {
    obtainParametersForGTSTermination(value, parForHybridAlg.parameterForGtsTerminateForImprovement, cusNum, "ForImprovement");
    parForHybridAlg.maxRunningTime = value["maxRunningTime"].asInt();
    parForHybridAlg.setCrossoverStrategy(value["crossoverStrategy"].asString());
    parForHybridAlg.ratioOfFinalStepsToInitialSteps = value["ratioOfFinalStepsToInitialSteps"].asInt();
    obtainParametersForPopulation(value, parForHybridAlg.parameterForPopulation, cusNum);
    obtainParametersForPathRelinking(value, parForHybridAlg.parameterForCrossoverOperators.parameterForPathRelinking);
    obtainParametersForGPX(value, parForHybridAlg.parameterForCrossoverOperators.parameterForGPX, depotNum);
}

void ReadParameters::obtainParametersForObtainBestMoveAndGain(const Json::Value &value,
                                                              ParForObtainBestMove &parForObtainBestMove, int cusNum) {
    parForObtainBestMove.setRespiration(value["respiration"].asString());
    parForObtainBestMove.setLSStrategy(value["lsStrategy"].asString());
    parForObtainBestMove.isTabuInvalidAfterChangeMoveType = value["isTabuInvalidAfterChangeMoveType"].asBool();
    parForObtainBestMove.isAttTabuUsed = value["isAttTabuUsed"].asBool();
    parForObtainBestMove.isSolTabuUsed = value["isSolTabuUsed"].asBool();
    parForObtainBestMove.setCusInEachMove(cusNum, value["cusRatioInEachMove"].asDouble());
}

void
ReadParameters::obtainParameters(string &filename, ParameterForRoutesRelatedProblem &parameterForRoutesRelatedProblem,
                                 int cusNum, int depotNum)
{
    fstream fs;
    fs.open(filename, ios::in);
    Json::Value value;
    Json::CharReaderBuilder jsonReader;
    string error;

    if (parseFromStream(jsonReader, fs, &value, &error))
    {
        obtainParametersForGTSControl(value,parameterForRoutesRelatedProblem.parameterForGranularTabuSearch.parameterForGTSControl,cusNum);
        obtainParametersForAttTabu(value, parameterForRoutesRelatedProblem.parameterForGranularTabuSearch.parForAttTabu, cusNum);
        obtainParametersForSolTabu(value, parameterForRoutesRelatedProblem.parameterForGranularTabuSearch.parForSolTabu);
        obtainParametersForPenaltyFactor(value, parameterForRoutesRelatedProblem.parameterForGranularTabuSearch.parameterForPenaltyFactor);
        obtainParametersForGTSTermination(value, parameterForRoutesRelatedProblem.parameterForGranularTabuSearch.parameterForGTSTermination, cusNum);
        obtainParametersForDiversity(value, parameterForRoutesRelatedProblem.parameterForGranularTabuSearch.parameterForDiversity, cusNum);
        obtainParametersForObtainBestMoveAndGain(value, parameterForRoutesRelatedProblem.parameterForGranularTabuSearch.parForObtainBestMove, cusNum);
        obtainParametersForRoutesPool(value, parameterForRoutesRelatedProblem.parameterForRoutesPool, cusNum);
        obtainParametersForHybridAlg(value, parameterForRoutesRelatedProblem.parameterForHybridAlg, cusNum, depotNum);
        obtainParametersForSolveStrategy(value, parameterForRoutesRelatedProblem.parameterForSolveStrategy);
        obtainParametersForChooseMoveTypes(value,parameterForRoutesRelatedProblem.parameterForGranularTabuSearch.parameterForChooseMoveTypes,cusNum);
    }
    fs.close();
}
